/**
 *@描述: react-router-dom6路由统一封装，添加路由守卫，路由加载效果
 *@author: hl 2298923519
 *@date:2022/6/8
 *@author:heli
 */
import {useRoutes, RouteObject, Navigate, useLocation} from 'react-router-dom';
import React, {Suspense} from "react";
type ReactNode = React.ReactNode;
interface FunctionRule {
    (): any
}
//meta规则
interface MetaRule {
    auth ?: boolean, //是否需要登录验证
    title ?: string, //页面title
    [name:string] : string | boolean, //其他参数
}

//单个路由规则
interface RouteObjectRule extends RouteObject {
    children ?: RouteObjectRule[], //子路由
    page ?: FunctionRule, //route导入页面的对象
    path ?: string, //页面路径
    redirect ?: string, //重定向地址 ，常用于设置页面默认地址
    meta ?: MetaRule, //页面参数
}

interface onRouteBeforeRule<meta = MetaRule , to = string> {
    (meta : meta, to : to) : any | never
}


interface GuardRule {
    routers : RouteObjectRule[], //路由对象
    onRouterBefore ?: onRouteBeforeRule, //路由权限函数
    loading ?: ReactNode,   //加载动画 传入Suspense的fallback
}

let onRouterBefore : onRouteBeforeRule;
let RouterLoading : FunctionRule;

//路由导航，设置redirect重定向 和 auth权限
function Guard ({ element, meta}) {
    const { pathname } = useLocation();
    const nextPath = onRouterBefore ? onRouterBefore(meta ,pathname) : pathname;
    if (nextPath && nextPath !== pathname) {
        element = <Navigate to={nextPath} replace={true}/>;
    }
    return element;
}


// 路由懒加载
function lazyLoadRouters(page, meta){
    meta = meta || {};
    const LazyElement = React.lazy(page);
    const GetElement = ()=> {
        return (
            <Suspense fallback={<RouterLoading/>}>
                <LazyElement/>
            </Suspense>
        );
    };
    return <Guard element={<GetElement/>} meta={meta}/>;
}

function transRoutes(routes : RouteObjectRule[]) {
    const list = [];
    routes.forEach(route => {
        const obj = { ...route };
        if (obj.redirect) {
            obj.element = <Navigate to={obj.redirect} replace={true} />
        }
        if (obj.page) {
            obj.element = lazyLoadRouters(obj.page, obj.meta)
        }
        if (obj.children) {
            obj.children = transRoutes(obj.children)
        }
        ['redirect','page','meta'].forEach(name => delete obj[name]);
        list.push(obj)
    });
    return list
}

export type {
    RouteObjectRule,
    MetaRule,
    FunctionRule,
    onRouteBeforeRule,
    ReactNode,
}

export default function (params : GuardRule){
    onRouterBefore = params.onRouterBefore; //路由守卫函数
    RouterLoading = ()=> params.loading || false;  //路由的loading节点
    return useRoutes(transRoutes(params.routers)); //路由数组，进行加载，转换
}
